package springapp.service;

import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import springapp.dao.CompanyDao;
import springapp.entity.CompanyEntity;
import springapp.entity.DesignationEntity;
import springapp.entity.LocationEntity;
import springapp.entity.ReviewEntity;
import springapp.entity.SalaryEntity;
import springapp.util.Utils;

@Service
public class CompanyService {

	private static final String COMPANY_ID = "companyId";

	@Autowired
	private CompanyDao companyDao;

	@Autowired
	private IIndustryService industryService;
	
	@Autowired
	private SalaryService salaryService;
	
	@Autowired
	private ReviewService reviewService;
	
	@PostConstruct
	/**
	 * populate the numReviews & numSalaries for each entity
	 */
	public void init(){
		this.companyDao.setInitialized();
		
	}

	@Transactional(readOnly = true)
	public List<CompanyEntity> getAllCompanies() {
		return companyDao.getAllEntities();
	}

	@Transactional
	public void addCompany(String companyName, String hq, Integer industryId,
			Set<LocationEntity> locationEntities) {
		CompanyEntity entity = new CompanyEntity();
		entity.setCompanyName(companyName);
		entity.setHeadquarters(hq);
		entity.setIndustryId(industryId);
		entity.setLocations(locationEntities);
		this.companyDao.saveEntity(entity);
	}

	@Transactional
	/*
	 * just send rating here,no need to add designations on every review
	 */
	public CompanyEntity addReview(int companyId, ReviewEntity reviewEntity,
			DesignationEntity designationEntity) {
		CompanyEntity entity = this.companyDao.getEntity(companyId);
		entity.getDesignations().add(designationEntity);
		Float currentRating = entity.getRating() == null ? (float) 0 : entity
				.getRating();
		int numReviews = entity.getNumReviews();
		float weightedAverage = Utils.getWeightedAverage(currentRating,
				numReviews - 1, reviewEntity.getRating());
		entity.setRating(weightedAverage);
		entity.setNumReviews(numReviews + 1);
		this.companyDao.updateEntity(entity);
		return entity;
	}

	@Transactional
	public CompanyEntity updateCompany(int companyId, String hqName,
			Integer industryId, Set<LocationEntity> locations) {
		CompanyEntity companyEntity = this.companyDao.getEntity(companyId);
		companyEntity.setHeadquarters(hqName);
		companyEntity.setIndustryId(industryId);
		companyEntity.setLocations(locations);
		this.companyDao.updateEntity(companyEntity);
		return companyEntity;
	}

	@Transactional
	/*
	 * no need to add designation on every salary
	 */
	public CompanyEntity addSalary(int companyId, SalaryEntity salaryEntity,
			DesignationEntity designationEntity) {
		CompanyEntity entity = this.companyDao.getEntity(companyId);
		entity.getDesignations().add(designationEntity);
		this.companyDao.updateEntity(entity);
		return entity;
	}

	public void setIndustryName(CompanyEntity... companyEntities) {
		for (CompanyEntity companyEntity : companyEntities) {
			companyEntity.setIndustryName(this.industryService
					.getIndustryName(companyEntity.getIndustryId()));
		}
	}

	@Transactional(readOnly = true)
	public CompanyEntity getCompany(Integer companyId) {
		SimpleExpression eq = Restrictions.eq(COMPANY_ID, companyId);
		return companyDao.findByCriteria(new Criterion[] { eq }).get(0);
	}

}
